#include "sht1x_v3.h"

static SHT1x_V3 sht1x_v3;

//----------------------------------------------------------------------------------
char read_byte(unsigned char ack)
//----------------------------------------------------------------------------------
// reads a byte form the Sensibus and gives an acknowledge in case of "ack=1"
{
    unsigned char i, val = 0;
    DATA_Q;  // ->>
    DATA_H;                       //release DATA-line

    DATA_I;  // <<-
 
    SCK_Q;  // ->>
    for (i = 0x80; i > 0; i /= 2) //shift bit for masking
    {
        SCK_H; //clk for SENSI-BUS
        if (DATA_R)
            val = (val | i); //read bit
        SCK_L;
    }
    //in case of "ack==1" pull down DATA-Line
    DATA_Q;  // ->>
    if (ack == 1) // 拉低响应
    {
        DATA_L;
    }
    SCK_H; //clk #9 for ack
    mgos_usleep(3);
    SCK_L;
    mgos_usleep(1);
    DATA_H; //release DATA-line
    return val;
}

char write_byte(unsigned char value)
//----------------------------------------------------------------------------------
// writes a byte on the Sensibus and checks the acknowledge
{
    unsigned char i, error = 0;
    
    SCK_Q;  // -->
    DATA_Q; // -->

    for (i = 0x80; i > 0; i /= 2)
    { //shift bit for masking
        if (i & value)
            DATA_H; //masking value with i , write to SENSI-BUS
        else
            DATA_L;
        mgos_usleep(1);
        SCK_H; //clk for SENSI-BUS
        mgos_usleep(3);
        SCK_L;
        mgos_usleep(1);
    }
    DATA_H;       //release DATA-line
    mgos_usleep(1);
    SCK_H;        //clk #9 for ack

    DATA_I;  // <<-

    error = DATA_R; //check ack (DATA will be pulled down by SHT11)
    SCK_L;
    if (error >= 1)
        printf("write byte error\n");
    return error; //error=1 in case of no acknowledge
}


//----------------------------------------------------------------------------------
void transstart(void)
//----------------------------------------------------------------------------------
// generates a transmission start
//       _____         ________
// DATA:      |_______|
//           ___     ___
// SCK : ___|   |___|   |______
{
    SCK_Q;  // ->>
    DATA_Q;  // ->>
        
    SCK_L; 
    DATA_H;//Initial state

    mgos_usleep(1);
    SCK_H;
    mgos_usleep(1);
    DATA_L;
    mgos_usleep(1);
    SCK_L;
    mgos_usleep(1);
    SCK_H;
    mgos_usleep(1);
    DATA_H;
    mgos_usleep(1);
    SCK_L;
}

//----------------------------------------------------------------------------------
void connectionreset(void)
//----------------------------------------------------------------------------------
// communication reset: DATA-line=1 and at least 9 SCK cycles followed by transstart
//       _____________________________________________________         ________
// DATA:                                                      |_______|
//          _    _    _    _    _    _    _    _    _        ___     ___
// SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |___|   |______
{
    unsigned char i;
    SCK_Q;
    DATA_Q;

    SCK_L; 
    DATA_H;//Initial state
                     
    for (i = 0; i < 9; i++) //9 SCK cycles
    {
        SCK_H;
        SCK_L;
    }
    transstart(); //transmission start
}

//----------------------------------------------------------------------------------
char softreset(void)
//----------------------------------------------------------------------------------
// resets the sensor by a softreset
{
    unsigned char error = 0;
    connectionreset();          //reset communication
    error += write_byte(RESET); //send RESET-command to sensor
    return error;               //error=1 in case of no response form the sensor
}

//----------------------------------------------------------------------------------
char read_statusreg(unsigned char *p_value, unsigned char *p_checksum)
//----------------------------------------------------------------------------------
// reads the status register with checksum (8-bit)
{
    unsigned char error = 0;
    transstart();                     //transmission start
    error = write_byte(STATUS_REG_R); //send command to sensor
    *p_value = read_byte(ACK);        //read status register (8-bit)
    *p_checksum = read_byte(noACK);   //read checksum (8-bit)
    return error;                     //error=1 in case of no response form the sensor
}

//----------------------------------------------------------------------------------
char write_statusreg(unsigned char *p_value)
//----------------------------------------------------------------------------------
// writes the status register with checksum (8-bit)
{
    unsigned char error = 0;
    transstart();                      //transmission start
    error += write_byte(STATUS_REG_W); //send command to sensor
    error += write_byte(*p_value);     //send value of status register
    return error;                      //error>=1 in case of no response form the sensor
}

// 回调：等待DATA
static void cb_wait_data(void *arg)
{
    DATA_I;  // <<-

    if (!DATA_R)
    {
        SHT1x_V3 *sht1x = (SHT1x_V3 *)arg;
        char msb = read_byte(ACK); //read the first byte (MSB)
        char lsb = read_byte(ACK); //read the second byte (LSB)
        float value = (float)(msb * 256 + lsb);
        if (sht1x->mode == MEASURE_TEMP)
        {
            sht1x->t = value;
        }
        else if (sht1x->mode == MEASURE_HUM)
        {
            sht1x->h = value;
        }
        calc_sth11(sht1x);
        //printf("value is :%f\n", value);
        sht1x->checksum = read_byte(noACK); //read checksum
        //arg = sht1x;
    }
}

//----------------------------------------------------------------------------------
void measure(unsigned char mode)
//----------------------------------------------------------------------------------
// makes a measurement (humidity/temperature) with checksum
{
    int wait = 320;
    sht1x_v3.error = 0;
    sht1x_v3.mode = mode;
    transstart(); //transmission start
    switch (mode)
    { //send command to sensor
    case MEASURE_TEMP:
        sht1x_v3.error += write_byte(MEASURE_TEMP);
        break;
        wait = 320;
    case MEASURE_HUM:
        sht1x_v3.error += write_byte(MEASURE_HUM);
        break;
        wait = 80;
    default:
        break;
    }
    // 等待：测温等待320ms，测湿度等待80ms
    // for (i=0;i<65535;i++) if(DATA==0) break;
    mgos_set_timer(wait, false, cb_wait_data, &sht1x_v3);
}

//----------------------------------------------------------------------------------------
void calc_sth11(SHT1x_V3 *sht1x)
//----------------------------------------------------------------------------------------
// calculates temperature [℃] and humidity [%RH]
// input :  hum [Ticks] (12 bit)
//          temp [Ticks] (14 bit)
// output:  hum
//          temp
{
    const float C1 = -2.0468;       // for 12 Bit RH
    const float C2 = +0.0367;       // for 12 Bit RH
    const float C3 = -0.0000015955; // for 12 Bit RH
    const float T1 = +0.01;         // for 12 Bit RH
    const float T2 = +0.00008;      // for 12 Bit RH

    float h = sht1x->h; // h:      Humidity [Ticks] 12 Bit
    float t = sht1x->t; // t:       Temperature [Ticks] 14 Bit
    float h_lin;        // h_lin:  Humidity linear
    float h_true;       // h_true: Temperature compensated humidity
    float t_C;          // t_C   :  Temperature [℃]

    t_C = t * 0.01 - 40.1;                       //calc. temperature [℃] from 14 bit temp. ticks @ 5V
    h_lin = C3 * h * h + C2 * h + C1;            //calc. humidity from ticks to [%RH]
    h_true = (t_C - 25) * (T1 + T2 * h) + h_lin; //calc. temperature compensated humidity [%RH]
    if (h_true > 100)
        h_true = 100; //cut if the value is outside of
    if (h_true < 0.1)
        h_true = 0.1; //the physical possible range

    sht1x->t_true = t_C;    //return temperature [℃]
    sht1x->h_true = h_true; //return humidity[%RH]
    //printf("t:%2.1f,h:%2.1f\n", t_C, h_true);
}

//--------------------------------------------------------------------
float calc_dewpoint(float h, float t)
//--------------------------------------------------------------------
// calculates dew point
// input:   humidity [%RH], temperature [℃癈]
// output:  dew point [℃]
{
    float k, dew_point;

    k = (log10(h) - 2) / 0.4343 + (17.62 * t) / (243.12 + t);
    dew_point = 243.12 * k / (17.62 - k);
    return dew_point;
}

//返回t/h
SHT1x_V3 get_sht1x(void) {
    return sht1x_v3;
}
